package com.share.payment.service.impl;

import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.share.common.core.domain.R;
import com.share.common.core.exception.ServiceException;
import com.share.common.core.utils.ServletUtils;
import com.share.common.core.utils.StringUtils;
import com.share.common.core.utils.ip.IpUtils;
import com.share.payment.config.WxPayV2Properties;
import com.share.payment.domain.CreateWxPaymentForm;
import com.share.payment.domain.PaymentInfo;
import com.share.payment.domain.WxPrepayVo;
import com.share.payment.service.IWxService;
import com.share.user.api.RemoteUserInfoService;
import com.share.user.api.domain.UserInfo;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

/**
 * @author ZhouShuang
 * @version 17
 * @Title
 * @date 2025/10/25 上午9:01
 */
@Service
@RequiredArgsConstructor
public class WxService implements IWxService {
    private final PaymentInfoService paymentInfoService;
    private final WxPayV2Properties wxPayV2Properties;
    private final WxPayService wxPayService;
    private final RemoteUserInfoService remoteUserInfoService;

    /**
     * 微信下单
     *
     * @param createWxPaymentForm
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public WxPrepayVo createWxPayment(CreateWxPaymentForm createWxPaymentForm) {
        try {
            // 1 向数据库中的payment_info表中插入一条支付数据
            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(createWxPaymentForm.getOrderNo());

            // 2 创建微信统一下单请求
            //远程调用获取用户信息信息
            R<UserInfo> userInfoResult = remoteUserInfoService.getUserInfo(paymentInfo.getUserId());
            if (StringUtils.isNull(userInfoResult) || StringUtils.isNull(userInfoResult.getData())) {
                throw new ServiceException("获取用户信息失败");
            }
            WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = getUnifiedOrderRequest(userInfoResult,createWxPaymentForm.getOrderNo());
            WxPayUnifiedOrderResult wxOrderResponse = wxPayService.unifiedOrder(wxPayUnifiedOrderRequest);
            WxPrepayVo wxPrepayVo = new WxPrepayVo();
            wxPrepayVo.setAppId(wxOrderResponse.getAppid());
            wxPrepayVo.setTimeStamp(timeToStr(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss"));
            wxPrepayVo.setNonceStr(wxOrderResponse.getNonceStr());
            wxPrepayVo.setPackageVal("prepay_id=" + wxOrderResponse.getPrepayId());
            wxPrepayVo.setSignType("MD5");
            wxPrepayVo.setPaySign(generatedMD5String(wxPrepayVo));
            //更新支付记录信息
            paymentInfo.setPaymentStatus(0);
            paymentInfoService.updateById(paymentInfo);
            return wxPrepayVo;
        } catch (WxPayException e) {
            throw new ServiceException(e.getMessage());
        } catch (Exception e) {
            throw new ServiceException("下单失败！");
        }
    }

    @Override
    public WxPayOrderQueryResult queryPayStatus(String orderNo) {
        //封装查询参数
        WxPayOrderQueryRequest wxPayOrderQueryRequest = new WxPayOrderQueryRequest();
        wxPayOrderQueryRequest.setOutTradeNo(orderNo);
        wxPayOrderQueryRequest.setAppid(wxPayV2Properties.getAppid());
        wxPayOrderQueryRequest.setMchId(wxPayV2Properties.getMerchantId());
        wxPayOrderQueryRequest.setNonceStr(getRandomString(32));
        try {
            wxPayOrderQueryRequest.setSign(MD5("appid="+wxPayV2Properties.getAppid()+"&mch_id="+wxPayV2Properties.getMerchantId()+"nonce_str"+wxPayOrderQueryRequest.getNonceStr()+"&out_trade_no="+orderNo+"&key="+wxPayV2Properties.getApiV2key()));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        try {
            return wxPayService.queryOrder(wxPayOrderQueryRequest);
        } catch (WxPayException e) {
            throw new ServiceException(e.getMessage());
        }

    }

    private String generatedMD5String(WxPrepayVo wxPrepayVo) throws Exception {
        String stringA = "appId=" + wxPrepayVo.getAppId() +
                "&nonceStr=" + wxPrepayVo.getNonceStr() +
                "&package=" + wxPrepayVo.getPackageVal() +
                "&signType=" + wxPrepayVo.getSignType() +
                "&timeStamp=" + wxPrepayVo.getTimeStamp();
        return MD5(stringA + "&key=" + wxPayV2Properties.getApiV2key());
    }

    private @NotNull WxPayUnifiedOrderRequest getUnifiedOrderRequest(R<UserInfo> userInfoResult, String orderNo) {
        if (R.FAIL == userInfoResult.getCode()) {
            throw new com.share.common.core.exception.ServiceException(userInfoResult.getMsg());
        }
        String openid = userInfoResult.getData().getWxOpenId();

        //构建下单请求对象
        WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
        wxPayUnifiedOrderRequest.setOutTradeNo(orderNo);
        wxPayUnifiedOrderRequest.setBody("小谷充电宝-归还结算");
        wxPayUnifiedOrderRequest.setOpenid(openid);
        wxPayUnifiedOrderRequest.setTotalFee(1); //这里方便测试直接写1即可
        wxPayUnifiedOrderRequest.setNotifyUrl(wxPayV2Properties.getNotifyUrl());
        wxPayUnifiedOrderRequest.setTradeType(wxPayV2Properties.getTradeType());
        wxPayUnifiedOrderRequest.setSpbillCreateIp(IpUtils.getIpAddr());
        wxPayUnifiedOrderRequest.setNonceStr(getRandomString(32));
        return wxPayUnifiedOrderRequest;
    }

    private String timeToStr(Long time, String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        if (time.toString().length() < 13) {
            time = time * 1000L;
        }
        Date date = new Date(time);
        return dateFormat.format(date);
    }

    private String MD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    private  String getRandomString(int length) {
        //定义一个字符串(A-Z，a-z，0-9)即62位；
        String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
        //由Random生成随机数
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        //长度为几就循环几次
        for (int i = 0; i < length; i++) {
            //产生0-61的数字
            int number = random.nextInt(62);
            //将产生的数字通过length次承载到sb中
            sb.append(str.charAt(number));
        }
        //将承载的字符转换成字符串
        return sb.toString();
    }
}
